﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using SqlOrm.Xml;

namespace SqlOrm
{
    public class DataTypes : List<DataType>
    {
        private void Add(string sql, string clr, string drmethod, bool nullable = false)
        {
            Add(new DataType(sql, clr, drmethod, nullable));
        }
        public static DataTypes All()
        {
            var dt = new DataTypes();
            dt.Add("bit", "bool", "GetBoolean({0})");
            dt.Add("tinyint", "byte", "GetByte({0})");
            dt.Add("smallint", "Int16", "GetInt16({0})");
            dt.Add("int", "int", "GetInt32({0})");
            dt.Add("bigint", "long", "GetInt64({0})");
            dt.Add("smallmoney", "decimal", "GetDecimal({0})");
            dt.Add("money", "decimal", "GetDecimal({0})");
            dt.Add("decimal", "decimal", "GetDecimal({0})");
            dt.Add("numeric", "decimal", "GetDecimal({0})");
            dt.Add("real", "Single", "GetFloat({0})");
            dt.Add("float", "double", "GetDouble({0})");
            dt.Add("char", "char", "GetChar({0})");
            dt.Add("nchar", "char", "GetChar({0})");
            //array of chars should rather be called strings maybe???

            dt.Add("varchar", "string", "GetString({0})", true);
            dt.Add("nvarchar", "string", "GetString({0})", true);
            dt.Add("text", "string", "GetString({0})", true);
            dt.Add("ntext", "string", "GetString({0})", true);
            dt.Add("xml", "string", "GetString({0})", true);
            dt.Add("smalldatetime", "DateTime", "GetDateTime({0})");
            dt.Add("datetime", "DateTime", "GetDateTime({0})");
            dt.Add("datetime2", "DateTime", "GetDateTime({0})");
            dt.Add("datetimeoffset", "DateTimeOffset", "GetDateTimeOffset({0})");
            dt.Add("date", "DateTime", "GetDateTime({0})");
            dt.Add("time", "TimeSpan", "GetTimeSpan({0})");
            dt.Add("binary", "byte[]", "GetBytes({0})", true);
            dt.Add("varbinary", "byte[]", "GetBytes({0})", true);
            dt.Add("image", "byte[]", "GetBytes({0})", true);
            dt.Add("timestamp", "byte[]", "GetBytes({0})", true);
            dt.Add("filestream", "byte", "GetByte({0})");
            dt.Add("uniqueidentifier", "Guid", "GetGuid({0})");
            dt.Add("sql_variant", "object", "GetValue({0})", true);

            return dt;
        }
    }
    public class DataType
    {
        public DataType(string sql, string clr, string drmethod, bool nullable)
        {
            SqlDataType = sql;
            ClrDataType = clr;
            DataReaderMethod = drmethod;
            Nullable = nullable;
        }
        public string ClrDataType { get; set; }
        public string SqlDataType { get; set; }
        public string DataReaderMethod { get; set; }
        public bool Nullable { get; set; }
    }
    public class DataTypeConversion
    {
        public static string GetDataReaderGetMethod(Field field)
        {
            return  DataTypes.All().Single(d => d.SqlDataType == GetSqlDbType(field)).DataReaderMethod;
        }

        public static string GetUnderlyingEnumDataType(Field field)
        {
            if (!string.IsNullOrEmpty(field.EnumName))
            {
                if (field.nulls)
                    return field.EnumName + "?";
                return field.EnumName;
            }
            return "ERROR";
        }

        public static string GetSQL(Field field)
        {
            return GetSqlDbType(field);
        }

        public static string GetSqlDbType(Field field)
        {
            var d = field.datatype.ToString().Replace("@", "");
            return d;
        }

        public static string GetCLRDataType(Field field)
        {
            if (!string.IsNullOrEmpty(field.EnumName))
            {
                if (field.nulls)
                    return field.EnumName + "?";
                else
                    return field.EnumName;
            }
            else
            {
                var dt = DataTypes.All().Single(d => d.SqlDataType == GetSqlDbType(field));
                string clrdatatype = dt.ClrDataType;
                //if ((dt.SqlDataType == "char" || dt.SqlDataType == "nchar") && field.len > 1)
                //    clrdatatype = "string";
                if (dt.Nullable)
                    return clrdatatype;
                else
                    return field.nulls ? clrdatatype + "?" : clrdatatype;
            }
        }

        public static bool IsNullableType(Field field)
        {
            return DataTypes.All().Single(x => x.SqlDataType == GetSqlDbType(field)).Nullable;
        }
    }
}
